﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using System.Xml.Linq;
using TeamsPortal.Configuration;
using TeamsPortal.DataAccess;
using TeamsPortal.ServiceClient;
using TeamsPortal.Validation;
using TeamsPortal.Web.Controllers.Filters;
using TeamsPortal.Web.Controllers.Helpers;
using TeamsPortal.Web.Extensions;
using TeamsPortal.Web.UI;

namespace TeamsPortal.Web.Controllers
{
	public class ForumsController : BaseController
	{
        private readonly ITopicsServiceClient _topicServiceClient;
        private readonly IForumsServiceClient _forumsServiceClient;

        public ForumsController(ITopicsServiceClient topicServiceClient
            , IForumsServiceClient forumsServiceClient
            )
        {
            _topicServiceClient = topicServiceClient;
            _forumsServiceClient = forumsServiceClient;
        }

		#region List
		public ActionResult List()
		{
            List<ForumCategory> list = _forumsServiceClient.GetList(User != null ? User.Id : 0);
			if (list.Count == 0)
			{
                ViewBag.ShowFirstSteps = !UsersServiceClient.IsThereAnyUser();
			}

			return View(list);
		}
		#endregion

		#region Manage
		[RequireAuthorization(UserRole.Moderator)]
		public ActionResult Manage()
		{
            var list = _forumsServiceClient.GetList(User != null ? User.Id : 0);
			return View(list);
		} 
		#endregion

		#region Detail
		[ValidateReadAccess]
		public ActionResult Detail(string forum, int page)
		{
			if (Config.UI.DefaultForumSort == ForumSort.LatestActivity)
			{
				return LatestTopics(forum, page, ResultFormat.Html);
			}
			return MostViewedTopics(forum, page);
		} 
		#endregion

		#region Most Viewed topics
		[ValidateReadAccess]
		public ActionResult MostViewedTopics(string forum, int page)
		{
            Forum f = _forumsServiceClient.Get(forum);
			if (f == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
			//Get the topics of the forum
			//Must Paginate the topics on the backend (Can be too many topics)
            f.Topics = _topicServiceClient.GetByForum(f.Id, (page - 1) * Config.UI.TopicsPerPage + 1, Config.UI.TopicsPerPage - 1, Role);

			ViewData["Tags"] = TagsServiceClient.GetMostViewed(f.Id, Config.UI.TagsCloudCount);
			ViewData["Page"] = page;
			ViewData["TotalTopics"] = f.TopicCount;
            ViewBag.Template = Template;

			return View("Detail", f);
		}
		#endregion

		#region Latest topics
		[ValidateReadAccess]
		public ActionResult LatestTopics(string forum, int page, ResultFormat format)
		{
            Forum f = _forumsServiceClient.Get(forum);
			if (f == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
            
			//Get the topics of the forum
			//Must Page the topics on the backend (Can be too many topics)
            if (format == ResultFormat.Html)
            {
                f.Topics = _topicServiceClient.GetLatest(f.Id, (page - 1) * Config.UI.TopicsPerPage + 1, Config.UI.TopicsPerPage - 1, Role, User != null ? User.Id : default(int));
                ViewBag.Template = Template;
                ViewData["Tags"] = TagsServiceClient.GetMostViewed(f.Id, Config.UI.TagsCloudCount);
                ViewData["Page"] = page;
                ViewData["TotalTopics"] = f.TopicCount;

                return View("Detail", f);
            }
            else
            {
                f.Topics = _topicServiceClient.GetLatest(f.Id, (page - 1) * Config.UI.TopicsPerPage + 1, Config.UI.TopicsPerPage - 1, Role);
                var list = from t in f.Topics
                           select new XElement("item",
                               new XElement("title", t.Title),
                               new XElement("link", string.Format("{0}{1}", Domain, Url.Action("ShortUrl", "Topics", new { id = t.Id }))),
                               new XElement("guid", string.Format("{0}{1}", Domain, Url.Action("ShortUrl", "Topics", new { id = t.Id }))),
                               new XElement("description", Utils.RemoveTags(t.Description)),
                               new XElement("pubDate", t.Date.ToApplicationDateTime().ToString("r", new CultureInfo("en-US"))));

                var doc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("rss",
                                 new XAttribute("version", "2.0"),
                                 new XElement("channel",
                                              new XElement("title", S("Latest threads on '{0}' forum", f.Name)),
                                              new XElement("link",
                                                           string.Format("{0}{1}", Domain, Url.Action("Detail",
                                                                                                      new
                                                                                                          {
                                                                                                              forum =
                                                                                                          f.ShortName
                                                                                                          }))),
                                              new XElement("description", Utils.RemoveTags(f.Description)),
                                              list.ToList<XElement>()
                                     )
                        )
                    );
                
                return Content(doc.Declaration + doc.ToString(SaveOptions.DisableFormatting), "text/xml");
            }
		}

		/// <summary>
		/// Get the latest topics on all forums
		/// </summary>
		/// <returns></returns>
		public ActionResult LatestAllTopics()
        {
            List<Topic> topics = _topicServiceClient.GetLatest();
		    var list = from t in topics
		               select new XElement("item",
                           new XElement("title", t.Title),
                           new XElement("link", string.Format("{0}{1}", Domain, Url.Action("ShortUrl", "Topics", new { id = t.Id }))),
                           new XElement("guid", string.Format("{0}{1}", Domain, Url.Action("ShortUrl", "Topics", new { id = t.Id }))),
                           new XElement("description", Utils.RemoveTags(t.Description)),
                           new XElement("pubDate", t.Date.ToApplicationDateTime().ToString("r", new CultureInfo("en-US"))));

            var doc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("rss",
                                 new XAttribute("version", "2.0"),
                                 new XElement("channel",
                                              new XElement("title", S("Latest threads on all forums")),
                                              new XElement("link", Domain),
                                              new XElement("description", S("Latest threads on all forums at {0}", Domain)),
                                              list.ToList<XElement>()
                                     )
                        )
                    );
			
            return Content(doc.Declaration + doc.ToString(SaveOptions.DisableFormatting), "text/xml");
		}
		#endregion

		#region Unanswered topics
		[ValidateReadAccess]
		public ActionResult ListUnansweredTopics(string forum)
		{
			Forum f = _forumsServiceClient.Get(forum);
			if (f == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
            f.Topics = _topicServiceClient.GetUnanswered(f.Id, Role);
            ViewBag.Template = Template;

			return View(f);
		}

		[RequireAuthorization(UserRole.Moderator)]
		public ActionResult ListAllUnansweredTopics()
		{
            List<Topic> topics = _topicServiceClient.GetUnanswered();
            ViewBag.Template = Template;
			
            return View(topics);
		}
		#endregion

		#region Add / Edit / Delete
		#region Add
		[HttpGet]
		[RequireAuthorization(UserRole.Moderator)]
		public ActionResult Add()
		{
            var roles = UsersServiceClient.GetRoles().Where(x => x.Key <= Role);
			ViewBag.UserRoles = new SelectList(roles, "Key", "Value");
			ViewBag.Categories = new SelectList(_forumsServiceClient.GetCategories(), "Id", "Name");
			return View("Edit");
		}

		[HttpPost]
		[RequireAuthorization(UserRole.Moderator)]
		[ValidateAntiForgeryToken]
		public ActionResult Add([Bind(Prefix = "", Exclude = "Id")] Forum forum)
		{
			try
			{
				if (!String.IsNullOrEmpty(forum.Name))
				{
                    forum.ShortName = forum.Name.ToUrlSegment(Forum.ShortNameLength);
				}
				if (ModelState.IsValid)
				{
					_forumsServiceClient.Add(forum, User.Id);
                    
                    return RedirectToAction("Detail", new { forum = forum.ShortName });
				}
			}
			catch (ValidationException ex)
			{
				this.AddErrors(this.ModelState, ex);
			}
            var roles = UsersServiceClient.GetRoles().Where(x => x.Key <= Role);
			ViewBag.UserRoles = new SelectList(roles, "Key", "Value");
			ViewBag.Categories = new SelectList(_forumsServiceClient.GetCategories(), "Id", "Name");
			
            return View("Edit", forum);
		} 
		#endregion

		#region Edit
		[HttpGet]
		[RequireAuthorization(UserRole.Moderator)]
		public ActionResult Edit(string forum)
		{
			Forum f = _forumsServiceClient.Get(forum);
			if (f == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
			if (!f.HasPostAccess(Role))
			{
				return ResultHelper.ForbiddenResult(this);
			}
            var roles = UsersServiceClient.GetRoles().Where(x => x.Key <= Role);
			ViewBag.UserRoles = new SelectList(roles, "Key", "Value");
			ViewBag.Categories = new SelectList(_forumsServiceClient.GetCategories(), "Id", "Name");
			ViewBag.IsEdit = true;
			
            return View("Edit", f);
		}

		[HttpPost]
		[RequireAuthorization(UserRole.Moderator)]
		[ValidateAntiForgeryToken]
		public ActionResult Edit(string forum, [Bind(Prefix = "")] Forum f)
		{
			try
			{
				#region Check access rights
				var originalForum = _forumsServiceClient.Get(forum);
				if (originalForum == null)
				{
					return ResultHelper.NotFoundResult(this);
				}
				if (!originalForum.HasPostAccess(Role))
				{
					return ResultHelper.ForbiddenResult(this);
				} 
				#endregion

				f.ShortName = forum;
				if (ModelState.IsValid)
				{
					_forumsServiceClient.Edit(f, User.Id);
					return RedirectToAction("Detail", new{forum=f.ShortName});
				}
			}
			catch (ValidationException ex)
			{
				AddErrors(this.ModelState, ex);
			}
            var roles = UsersServiceClient.GetRoles().Where(x => x.Key <= Role);
			ViewBag.UserRoles = new SelectList(roles, "Key", "Value");
			ViewBag.Categories = new SelectList(_forumsServiceClient.GetCategories(), "Id", "Name");
			ViewBag.IsEdit = true;
			
            return View("Edit", f);
		}
		#endregion

		#region Delete
		[AcceptVerbs(HttpVerbs.Post)]
		[RequireAuthorization(UserRole.Moderator)]
		[ValidateAntiForgeryToken]
		public ActionResult Delete(string forum)
		{
			_forumsServiceClient.Delete(forum);

			return RedirectToAction("Manage");
		}
		#endregion
		#endregion

		#region Tag detail
		[ValidateReadAccess]
		public ActionResult TagDetail(string forum, string tag, int page)
		{
			Forum f = _forumsServiceClient.Get(forum);
			if (f == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
            f.Topics = _topicServiceClient.GetByTag(tag, f.Id, Role);
			ViewData["Page"] = page;
			ViewData["Tag"] = tag;
            ViewBag.Template = Template;
			
            return View(f);
		}
		#endregion
	}
}
